//
//  NSObject+KVCChangeType.m
//  package
//
//  Created by WJC on 2018/10/30.
//  Copyright © 2018 wjc. All rights reserved.
//

#import "NSObject+KVCChangeType.h"

@implementation NSObject (KVCChangeType)
+ (void)swizzleSelector:(SEL)originalSelector withSwizzledSelector:(SEL)swizzledSelector
{
    Class class = [self class];
    
    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
    
        // 若已经存在，则添加会失败
    
    BOOL didAddMethod = class_addMethod(class,originalSelector,
                                        
                                        method_getImplementation(swizzledMethod),
                                        
                                        method_getTypeEncoding(swizzledMethod));
    
        // 若原来的方法并不存在，则添加即可
    
    if (didAddMethod) {
        
        class_replaceMethod(class,swizzledSelector,
                            
                            method_getImplementation(originalMethod),
                            
                            method_getTypeEncoding(originalMethod));
        
    } else {
        
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}
-(id)setKVCWithObj:(id)obj{
//    WJCLog(@"%@",NSStringFromClass([self class]));
    if ([obj isKindOfClass:[NSArray class]]) {
        NSMutableArray *returnArr=[NSMutableArray new];
        for (id object in obj) {
            const char *className = [NSStringFromClass([self class]) cStringUsingEncoding:NSASCIIStringEncoding];
            Class newClass = objc_getClass(className);
            id instance =[[newClass alloc] init];
            [returnArr addObject:[instance setKVCWithObj:object]];
        }
        return returnArr;
    }else if([obj isKindOfClass:[NSDictionary class]]){
       return [self setKVCobjectWithObj:obj];
    }else{
        return nil;
    }
}
-(id)setKVCobjectWithObj:(NSDictionary *)obj{
    {
//     WJCLog(@"%@",NSStringFromClass([self class]));
//    const char *className = [[self class] cStringUsingEncoding:NSASCIIStringEncoding];
//        // 从一个字串返回一个类
//    Class newClass = objc_getClass(className);
    if (obj) {
            // 创建对象
        id instance = self;
        if (!instance) {
            return nil;
        }
        // 对该对象赋值属性
        NSDictionary * propertys = obj;
        [propertys enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
            NSDictionary *dic = [self getPraviteFuncWithFuncName:@"getModel"];
            if (dic.count>0) {
                for (NSString *dicKey in dic) {
                    if ([dic[dicKey] isKindOfClass:[NSString class]]) {
                        if ([dic[dicKey] isEqual:key]) {
                            if ([self checkIsExistPropertyWithInstance:self verifyPropertyName:dic[dicKey] andLogAllProperty:NO]) {
                            [instance setObject:obj WithKey:dic[dicKey]];
                            }
                        }
                        else if ([self checkIsExistPropertyWithInstance:self verifyPropertyName:dic[dicKey] andLogAllProperty:NO]) {
                            
                             [instance setObject:obj WithKey:key];
                        }
                    }
                    else if([obj isKindOfClass:[NSArray class]]){
                        
                         if ([dicKey isEqual:key]) {
                             if ([self checkIsExistPropertyWithInstance:self verifyPropertyName:key andLogAllProperty:NO]){
                              NSMutableArray *addArr=[NSMutableArray new];
                            for (int i = 0 ; i < ((NSArray*)obj).count; i++) {
                                
                                    Class newClass =dic[dicKey];
                                id object=[[newClass alloc]init];
                                if (object) {
                                     [object setKVCWithObj:((NSArray*)obj)[i]];
                                                                   [addArr addObject:object];
                                }
                               
                                }
                                 [instance setValue:addArr forKey:dicKey];
//                                 [instance setva:addArr WithKey:dicKey];
                            }
                            
                         }else if ([self checkIsExistPropertyWithInstance:self verifyPropertyName:key andLogAllProperty:NO]) {
                             [instance setValue:obj forKey:key];
                         }
                        }
                    else if([obj isKindOfClass:[NSNull class]]){
                        continue;
                    }
                   else  if([obj isKindOfClass:[NSDictionary class]]){
                        const char *objName = [NSObject getControllerIvalWithController:instance andPropertyName:key];
                        NSString *objNameStr=[NSString stringWithFormat:@"%s",objName];
                        if(objNameStr.length>0&&!([objNameStr isEqual:@"NSMutableDictionary"]||[objNameStr isEqual:@"NSDictionary"])){
                            Class newClass = objc_getClass(objName);
                            id object=[[newClass alloc]init];
                            [object setKVCWithObj:obj];
                            [instance setValue:object forKey:key];
                        }else if ([self checkIsExistPropertyWithInstance:self verifyPropertyName:dic[dicKey] andLogAllProperty:NO]
                                  ||[self checkIsExistPropertyWithInstance:self.superclass verifyPropertyName:dic[dicKey] andLogAllProperty:NO]) {
                            [instance setObject:obj WithKey:key];
                        }
                    }
                   else  {
                        if ([self checkIsExistPropertyWithInstance:self verifyPropertyName:key andLogAllProperty:NO]||[self checkIsExistPropertyWithInstance:self.superclass verifyPropertyName:dic[dicKey] andLogAllProperty:NO])
                            [instance setObject:obj WithKey:key];
                    }
                        }
            }else{
                if ([self checkIsExistPropertyWithInstance:self verifyPropertyName:key andLogAllProperty:NO]||[self checkIsExistPropertyWithInstance:self.superclass verifyPropertyName:key andLogAllProperty:NO]) {
                    if([obj isKindOfClass:[NSDictionary class]]){
                        const char *objName = [NSObject getControllerIvalWithController:instance andPropertyName:key];
                        NSString *objNameStr=[NSString stringWithFormat:@"%s",objName];
                        if(objNameStr.length>0&&!([objNameStr isEqual:@"NSMutableDictionary"]||[objNameStr isEqual:@"NSDictionary"])){
                            Class newClass = objc_getClass(objName);
                            id object=[[newClass alloc]init];
                            [object setKVCWithObj:obj];
                            [instance setValue:object forKey:key];
                        }
                        else {
                            [instance setValue:obj forKey:key];
                        }
                    }else{
                         [instance setValue:obj forKey:key];
                    }
                }
                else if ([key isKindOfClass:[NSString class]]&&( [self checkIsExistPropertyWithInstance:self verifyPropertyName:((NSString*)key).capitalizedString andLogAllProperty:NO]||[self checkIsExistPropertyWithInstance:self.superclass verifyPropertyName:((NSString*)key).capitalizedString andLogAllProperty:NO])) {
                    if([obj isKindOfClass:[NSDictionary class]]){
                        const char *objName = [NSObject getControllerIvalWithController:instance andPropertyName:((NSString*)key).capitalizedString];
                        NSString *objNameStr=[NSString stringWithFormat:@"%s",objName];
                        if(objNameStr.length>0&&!([objNameStr isEqual:@"NSMutableDictionary"]||[objNameStr isEqual:@"NSDictionary"])){
                            Class newClass = objc_getClass(objName);
                            id object=[[newClass alloc]init];
                            [object setKVCWithObj:obj];
                            [instance setValue:object forKey:((NSString*)key).capitalizedString];
                        }
                        else {
                            [instance setObject:obj WithKey:((NSString*)key).capitalizedString];
                        }
                    }else{
                         [instance setObject:obj WithKey:((NSString*)key).capitalizedString];
                    }
                }
            }
                // 检测这个对象是否存在该属性
           
        }];
        return instance;
    }else{
        return self;
    }
    }
}
-(void)setObject:(id)object WithKey:(id)key{
    if ([object isKindOfClass:[NSNumber class]]) {
        if (strcmp([object objCType], @encode(BOOL)) == 0) {
             [self setValue:(bool)object?@(true):@(false) forKey:key];
        } else if (strcmp([object objCType], @encode(int)) == 0||strcmp([object objCType], @encode(float)) == 0 ||strcmp([object objCType], @encode(double)) == 0) {
            if ([[self valueForKey:key] isKindOfClass:[NSString class]]) {
                [self setValue:[NSString stringWithFormat:@"%@",object] forKey:key];
                return;
            }
           [self setValue:object forKey:key];
        }else{
             [self setValue:[NSString stringWithFormat:@"%@",object] forKey:key];
        }
         }if ([[self valueForKey:key] isKindOfClass:[NSString class]]) {
            [self setValue:[NSString stringWithFormat:@"%@",object] forKey:key];
           
        }
        else {
             [self setValue:object forKey:key];
        }
}
+(id)setKVCobjectWithObj:(NSDictionary *)obj andModelString:(NSString *)str {
        //    const char *className = [[self class] cStringUsingEncoding:NSASCIIStringEncoding];
        //        // 从一个字串返回一个类
        //    Class newClass = objc_getClass(className);
    const char *className = [str cStringUsingEncoding:NSASCIIStringEncoding];
        // 从一个字串返回一个类
    Class newClass = objc_getClass(className);
    id instance = [[newClass alloc] init];
    if (instance) {
        
    
    if (obj) {
            // 创建对象
        
            // 对该对象赋值属性
        NSDictionary * propertys = obj;
        [propertys enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
            NSDictionary *dic = [self getPraviteFuncWithFuncName:@"getModel"];
            
            if (dic.count>0) {
                for (NSString *dicKey in dic) {
                    if ([dic[dicKey] isKindOfClass:[NSString class]]) {
                        if ([dic[dicKey] isEqual:key]) {
                            if ([instance checkIsExistPropertyWithInstance:instance verifyPropertyName:dic[dicKey] andLogAllProperty:NO]) {
                                [instance setValue:obj forKey:dic[dicKey]];
                            }
                        }else if ([instance checkIsExistPropertyWithInstance:instance verifyPropertyName:dic[dicKey] andLogAllProperty:NO]) {
                            
                            [instance setValue:obj forKey:key];
                        }
                    }
                    else if([obj isKindOfClass:[NSArray class]]){
                        
                        if ([dicKey isEqual:key]) {
                            if ([instance checkIsExistPropertyWithInstance:instance verifyPropertyName:key andLogAllProperty:NO]){
                                NSMutableArray *addArr=[NSMutableArray new];
                                for (int i = 0 ; i < ((NSArray*)obj).count; i++) {
                                    
                                    Class newClass =dic[dicKey];
                                    id object=[[newClass alloc]init];
                                    [object setKVCWithObj:((NSArray*)obj)[i]];
                                    [addArr addObject:object];
                                }
                                [instance setValue:addArr forKey:dicKey];
                            }
                            
                        }else if ([instance checkIsExistPropertyWithInstance:instance verifyPropertyName:key andLogAllProperty:NO]) {
                            [instance setValue:obj forKey:key];
                        }
                    }
                    else  if([obj isKindOfClass:[NSDictionary class]]){
                        const char *objName = [NSObject getControllerIvalWithController:instance andPropertyName:key];
                        NSString *objNameStr=[NSString stringWithFormat:@"%s",objName];
                        if(objNameStr.length>0&&!([objNameStr isEqual:@"NSMutableDictionary"]||[objNameStr isEqual:@"NSDictionary"])){
                            Class newClass = objc_getClass(objName);
                            id object=[[newClass alloc]init];
                            [object setKVCWithObj:obj];
                            [instance setValue:object forKey:key];
                        }else if ([instance checkIsExistPropertyWithInstance:self verifyPropertyName:dic[dicKey] andLogAllProperty:NO]
                                  ||[instance checkIsExistPropertyWithInstance:self.superclass verifyPropertyName:dic[dicKey] andLogAllProperty:NO]) {
                            [instance setValue:obj forKey:key];
                        }
                    }else  {
                        if ([instance checkIsExistPropertyWithInstance:instance verifyPropertyName:key andLogAllProperty:NO]||[instance checkIsExistPropertyWithInstance:((NSObject*)instance).superclass verifyPropertyName:dic[dicKey] andLogAllProperty:NO]) [instance setValue:obj forKey:key];
                    }
                }
            }else{
                if ([instance checkIsExistPropertyWithInstance:instance verifyPropertyName:key andLogAllProperty:NO]||[instance checkIsExistPropertyWithInstance:((NSObject*)instance).superclass verifyPropertyName:key andLogAllProperty:NO]) {
                    if([obj isKindOfClass:[NSDictionary class]]){
                        const char *objName = [NSObject getControllerIvalWithController:instance andPropertyName:key];
                        NSString *objNameStr=[NSString stringWithFormat:@"%s",objName];
                        if(objNameStr.length>0&&!([objNameStr isEqual:@"NSMutableDictionary"]||[objNameStr isEqual:@"NSDictionary"])){
                            Class newClass = objc_getClass(objName);
                            id object=[[newClass alloc]init];
                            [object setKVCWithObj:obj];
                            [instance setValue:object forKey:key];
                        }
                        else {
                            [instance setValue:obj forKey:key];
                        }
                    }else{
                        [instance setValue:obj forKey:key];
                    }
                }
            }
                // 检测这个对象是否存在该属性
            
        }];
        return instance;
    }else{
        return instance;
    }
    }
    else{
        return nil;
    }
}
/**
 获取相应的控制器属性的对应类型
 
 @param controller 控制器
 @param verifyPropertyName 类型值
 @return 类型char
 */
+(const char*)getControllerIvalWithController:(id)controller andPropertyName:(NSString *)verifyPropertyName{
    const char *method="";
    const char *PropertyName = [[NSString stringWithFormat:@"_%@",verifyPropertyName] cStringUsingEncoding:NSASCIIStringEncoding];
    unsigned int methodCount = 0;
    Ivar * ivars = class_copyIvarList([controller class], &methodCount);
    for (unsigned int i = 0; i < methodCount; i ++) {
        Ivar ivar = ivars[i];
        const char * name = ivar_getName(ivar);
        const char * type = ivar_getTypeEncoding(ivar);
        if (strcmp(PropertyName, name) == 0) {
                //            NSMutableString *str=;
            method=[[[[NSMutableString stringWithFormat:@"%s",type] stringByReplacingOccurrencesOfString:@"\"" withString:@""] stringByReplacingOccurrencesOfString:@"@" withString:@""] cStringUsingEncoding:NSASCIIStringEncoding];
            break;
        }
        
    }
    free(ivars);
    return method;
}
+ (BOOL)checkIsExistMethodWithInstance:(id)instance verifyMethodName:(NSString *)verifyMethodName{
        //调用公共变量
        //    SEL sel = NSSelectorFromString(@"shareAlert");
        //    if ([self respondsToSelector:sel]) {
        //        [self performSelector:sel];
        //    }
        //    WJCLog(@"//控制器是否存在方法:%ld",[super checkIsExistPropertyWithverifyPropertyName:@"urlString"]);
        //先获取类名
    NSString *className = NSStringFromClass([instance class]);
    const char *cClassName = [className UTF8String];
    
    id theClass = objc_getClass(cClassName);
        //用来计数
    unsigned int outCount;
    
    Method *m =  class_copyMethodList(theClass,&outCount);
    BOOL isGet=NO;
    for (int i = 0; i<outCount; i++) {
        SEL a = method_getName(*(m+i));
        NSString *sn = NSStringFromSelector(a);
        if ([sn isEqualToString:verifyMethodName]) {
                //            [self performSelector:a];
            isGet=YES;
            break;
        }
    }
    free(m);
    

    return isGet;
}
/**
 检测对象是否存在该属性
 
 @param instance 控制器对象
 @param verifyPropertyName 控制器属性值
 @return 是否存在
 */
- (BOOL)checkIsExistPropertyWithInstance:(id)instance verifyPropertyName:(NSString *)verifyPropertyName andLogAllProperty:(BOOL)log
{
    unsigned int outCount, i;
        // 获取对象里的属性列表
    objc_property_t * properties = class_copyPropertyList([instance
                                                           class], &outCount);
    
    if(log){
        for (i = 0; i < outCount; i++) {
            objc_property_t property =properties[i];
                //  属性名转成字符串
            NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
            
            if(log){
                WJCLog(@"控制器拥有的成员属性名字为 %@ ",propertyName);
            }
        }
    }
    for (i = 0; i < outCount; i++) {
        objc_property_t property =properties[i];
            //  属性名转成字符串
        NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
            // 判断该属性是否存在
        if ([propertyName isEqual:verifyPropertyName]) {
            free(properties);
            return YES;
        }
    }
    free(properties);
    return NO;
}

/**
 runtime调用私有变量
 
 @param funcName 方法名
 */
-(NSDictionary*)getPraviteFuncWithFuncName:(NSString*)funcName{
        //调用公共变量
        //    SEL sel = NSSelectorFromString(@"shareAlert");
        //    if ([self respondsToSelector:sel]) {
        //        [self performSelector:sel];
        //    }
        //    WJCLog(@"//控制器是否存在方法:%ld",[super checkIsExistPropertyWithverifyPropertyName:@"urlString"]);
        //先获取类名
    NSString *className = NSStringFromClass([self class]);
    const char *cClassName = [className UTF8String];
    
    id theClass = objc_getClass(cClassName);
        //用来计数
    unsigned int outCount;
    
    Method *m =  class_copyMethodList(theClass,&outCount);
    for (int i = 0; i<outCount; i++) {
        SEL a = method_getName(*(m+i));
        NSString *sn = NSStringFromSelector(a);
        if ([sn isEqualToString:funcName]) {
            if ([self respondsToSelector:a]) {
                free(m);

          return [self performSelector:a];
            }else{
                free(m);
                return nil;
            }
        }
    }
    free(m);

    return nil;
}
-(id)skipGraphQLItems{
    if ([self isKindOfClass:[NSArray class]]) {
        NSMutableArray *arr=[NSMutableArray new];
        for (id object in self) {
            [arr addObject: [object skipGraphQLItems]];
        }
        return arr;
    }else if([self isKindOfClass:[NSDictionary class]]){
        NSMutableDictionary *dic=[NSMutableDictionary new];
        for (NSString *key in self) {
            if ([key.lowercaseString isEqual:@"items"]) {
                NSMutableArray *arr=[[NSMutableArray arrayWithArray:((NSMutableDictionary*)self)[key]] skipGraphQLItems];
                return arr;
            }else if([((NSDictionary*)self)[key] isKindOfClass:[NSDictionary class]]){
                [dic setObject:[((NSMutableDictionary*)self)[key] skipGraphQLItems] forKey:key];
               // ((NSMutableDictionary*)self)[key]=[((NSMutableDictionary*)self)[key] skipGraphQLItems];
            }else{
                [dic setObject:((NSMutableDictionary*)self)[key] forKey:key];
            }
        }
        return dic;
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)encoder

{
    unsigned int count = 0;
    Ivar *ivars = class_copyIvarList([self class], &count);
    
    for (int i = 0; i<count; i++) {
            // 取出i位置对应的成员变量
        Ivar ivar = ivars[i];
            // 查看成员变量
        const char *name = ivar_getName(ivar);
            // 归档
        NSString *key = [NSString stringWithUTF8String:name];
        id value = [self valueForKey:key];
        [encoder encodeObject:value forKey:key];
    }
    free(ivars);
}
- (id)decodeWithCoder:(NSCoder *)decoder
{
        unsigned int count = 0;
        Ivar *ivars = class_copyIvarList([self class], &count);
        for (int i = 0; i<count; i++) {
                // 取出i位置对应的成员变量
            Ivar ivar = ivars[i];
                // 查看成员变量
            const char *name = ivar_getName(ivar);
                // 归档
            NSString *key = [NSString stringWithUTF8String:name];
            id value = [decoder decodeObjectForKey:key];
                // 设置到成员变量身上
            [self setValue:value forKey:key];
            
        }
        free(ivars);
    return self;
}
    /// 该方法接收一个方法的签名,和一个可变参数
- (id)performSelector:(SEL)aSelector withObjects:(id)object,... {
        // 方法签名(方法的描述)
    NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:aSelector];
    if (signature == nil) {
        NSAssert(false, @"找不到 %@ 方法",NSStringFromSelector(aSelector));
    }
        // 包装方法
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
        // 设置方法调用者
    invocation.target = self;
        // 设置需要调用的方法
    invocation.selector = aSelector;
        // 获取除去self、_cmd以外的参数个数
    NSInteger paramsCount = signature.numberOfArguments - 2;
        // 设置参数
    va_list params;
    va_start(params, object);
    int i = 0;
        // [GKEndMark end] 是自定义的结束符号,仅此而已,从而使的该方法可以接收nil做为参数
    for (id tmpObject = object; (id)tmpObject != [[[self class] new] end]; tmpObject = va_arg(params, id)) {
            // 防止越界
        if (i >= paramsCount) break;
            // 去掉self,_cmd所以从2开始
        [invocation setArgument:&tmpObject atIndex:i + 2];
        i++;
    }
    va_end(params);
        // 调用方法
    [invocation invoke];
        // 获取返回值
    id returnValue = nil;
    if (signature.methodReturnType) {
        [invocation getReturnValue:&returnValue];
    }
    return returnValue;
}


@end
